package design.mode.currentLimit.com.xzg.ratelimiter2;

import design.mode.currentLimit.com.xzg.ratelimiter2.alg.FixedTimeWinRateLimitAlg;
import design.mode.currentLimit.com.xzg.ratelimiter2.alg.RateLimitAlg;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.ApiLimit;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.RateLimitRule;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.RuleConfig;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.TrieRateLimitRule;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.datasource.FileRuleConfigSource;
import design.mode.currentLimit.com.xzg.ratelimiter2.rule.datasource.RuleConfigSource;
import java.util.concurrent.ConcurrentHashMap;

/**
 * /**
 *
 * @author famous on 2021/12/11
 */

public class RateLimiter {

  // 为每个api在内存中存储限流计数器
  private ConcurrentHashMap<String, RateLimitAlg> counters = new ConcurrentHashMap<>();

  private RateLimitRule rule;

  public RateLimiter() {
    RuleConfigSource configSource = new FileRuleConfigSource();
    RuleConfig ruleConfig = configSource.load();
    // 将限流规则构建成支持快速查找的数据结构RateLimitRule
    this.rule = new TrieRateLimitRule(ruleConfig);
  }

  public boolean limit(String appId, String url) {
    ApiLimit apiLimit = rule.getLimit(appId, url);
    if (apiLimit == null) {
      return true;
    }
    // 获取api对应在内存中的限流计数器（rateLimitCounter）
    String counterKey = appId + ":" + apiLimit.getApi();
    RateLimitAlg rateLimitCounter = counters.get(counterKey);
    if (rateLimitCounter == null) {
      RateLimitAlg newRateLimitCounter = new FixedTimeWinRateLimitAlg(apiLimit.getLimit());
      rateLimitCounter = counters.putIfAbsent(counterKey, newRateLimitCounter);
      if (rateLimitCounter == null) {
        rateLimitCounter = newRateLimitCounter;
      }
    }
    // 判断是否限流
    return rateLimitCounter.tryAcquire();
  }
}
